﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Data;
using System.Data.SqlClient;

namespace Iit.ITBI.MDSManager
{
    class MasterToSlaveEntityMapping
    {

        public CustomEntitiy MasterEntity
        {
            get;
            set;
        }

        public CustomEntitiy SlaveEntity
        {
            get;
            set;
        }

        public MDSEntitySyncState EntitySyncState
        {
            get;
            set;
        }

        public MDSMappingState MappingState
        {
            get;
            set;
        }

        public Collection<MasterToSlaveAttributeMapping> MasterToSlaveAttributeMappings
        {
            get;
            set;
        }

        public int MappingCode
        {
            get;
            set;
        }

        public Collection<int> MembersMissingInMasterCodes
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets a value indicating whether the entity has only system attributes.
        /// </summary>
        /// <value>
        /// <c>true</c> if the entity has only system attributes; otherwise, <c>false</c>.
        /// </value>
        public bool HasOnlySystemAttributes
        {
            get;
            set;
        }

        //public MasterToSlaveEntityMapping(CustomEntitiy MasterEntity, CustomEntitiy SlaveEntity)
        //{
        //    this.MasterEntity = MasterEntity;
        //    this.SlaveEntity = SlaveEntity;

        //    this.EntitySyncState = MDSEntitySyncState.Unknown;
            
        //}

        public MasterToSlaveEntityMapping(DataRow MasterToSlaveMappingData, MDSQueryVersion QueryVersion)
        {
            this.MasterToSlaveAttributeMappings = new Collection<MasterToSlaveAttributeMapping>();

            this.MembersMissingInMasterCodes = new Collection<int>();

            if (QueryVersion == MDSQueryVersion.GetMasterToSlaveMappingV1)
            {
                this.MappingCode = Convert.ToInt16(MasterToSlaveMappingData["Mapping_Code"]);

                this.MasterEntity = new CustomEntitiy(MasterToSlaveMappingData, SlaveOrMaster.Master, QueryVersion);
                this.SlaveEntity = new CustomEntitiy(MasterToSlaveMappingData, SlaveOrMaster.Slave, QueryVersion);

                //apply the mapping state to the local property of the object
                //this will later on be used to determinate what to do with the mappings.
                UpdateMappingState(MasterToSlaveMappingData["MappingState"].ToString());

                this.EntitySyncState = MDSEntitySyncState.Unknown;
            }
            else
            {   
                throw new NotSupportedException(string.Format("Query Version {0} is not supported.", QueryVersion.ToString()));
            }

        }

        public void PopulateAttributesDetails (CustomDataTable AttributesDetails)
        {   
            if (AttributesDetails.QueryVersion == MDSQueryVersion.GetAttributeDetailesV1)
            { 

                string FilterEexpression;
                FilterEexpression = string.Format("Mapping_Code = '{0}'", this.MappingCode.ToString());
                DataRow[] FilteredRows;

                // Use the Select method to find all rows matching the current mapping code.
                FilteredRows = AttributesDetails.Select(FilterEexpression);

                if (FilteredRows.Length > 0)
                {
                    HasOnlySystemAttributes = false;

                    //for each row add an masterToSlaveAttributeMapping to the MasterToSlaveAttributeMappings collection
                    for (int i = 0; i < FilteredRows.Length; i++)
                    {
                        this.MasterToSlaveAttributeMappings.Add(new MasterToSlaveAttributeMapping(FilteredRows[i], AttributesDetails.QueryVersion));
                    }            

                }
                else
                {
                    HasOnlySystemAttributes = true;

                    //throw new InvalidMetadataException (string.Format("No rows found in the attribute list for the mapping code {0}", this.MappingCode.ToString()));
                }

                
            }
            else
            {   
                throw new NotSupportedException(string.Format("Query Version {0} is not supported.", AttributesDetails.QueryVersion.ToString()));
            }

        }

        public void PopulateMissingMembersInMaster(CustomDataTable DeletedMembers)
        {

            if (DeletedMembers.QueryVersion == MDSQueryVersion.DeletedMembersV1)
            {

                foreach (DataRow dr in DeletedMembers.Rows)
                {

                    MembersMissingInMasterCodes.Add(Convert.ToInt32(dr["Code"].ToString()));
            
                }

            }
            else
            {
                throw new NotSupportedException(string.Format("Query Version {0} is not supported.", DeletedMembers.QueryVersion.ToString()));
            }

        }

        public void SetEntitySyncState (CustomDataTable EntitiesSyncState)
        {   
            if (EntitiesSyncState.QueryVersion == MDSQueryVersion.GetEntitySyncStateV1)
            { 

                string FilterEexpression;
                FilterEexpression = string.Format("Mapping_Code = '{0}'", this.MappingCode.ToString());
                DataRow[] FilteredRows;

                // Use the Select method to find all rows matching the current mapping code.
                FilteredRows = EntitiesSyncState.Select(FilterEexpression);

                if(FilteredRows.Length == 0)
                {
                    throw new InvalidMetadataException (string.Format("No row found in the Entity sync state list for the mapping code {0}. Expected masterAttributeMetadata single row.", this.MappingCode.ToString()));
                }
                if(FilteredRows.Length > 1)
                {
                    throw new InvalidMetadataException (string.Format("Multiple rows found in the Entity sync state list for the mapping code {0}. Expected masterAttributeMetadata single row.", this.MappingCode.ToString()));
                }

                //assign the value to the local property
                try
                {
                    this.EntitySyncState = (MDSEntitySyncState)Convert.ToByte(FilteredRows[0]["EntitySyncState"]);

                    switch (this.EntitySyncState)
                    {
                        case MDSEntitySyncState.Unknown:

                            throw new UnknownSyncStateException(
                                    string.Format("The sync state for the mapping between the master Entity {0} and the slave Entity {1} is unknown"
                                                , this.MasterEntity.Name
                                                , this.SlaveEntity.Name));
                            break;
                    }

                }
                catch (InvalidSyncStateException e)
                {
                    throw;
                }
                catch (UnknownSyncStateException e)
                {
                    throw;
                }
                catch (Exception e)
                {
                    throw new Exception(string.Format("Failed to convert the sync state value {0}, for the mapping between the master Entity {1} and the slave Entity {2}."
                                                    , FilteredRows[0]["EntitySyncState"].ToString()
                                                    , this.MasterEntity.Name
                                                    , this.SlaveEntity.Name), e);
                }
                            
            }
            else
            {   
                throw new NotSupportedException(string.Format("Query Version {0} is not supported.", EntitiesSyncState.QueryVersion.ToString()));
            }

        }


        private void UpdateMappingState(string MappingState)
        {
            switch (MappingState)
            {
                case "Valid":
                    this.MappingState = MDSMappingState.Valid;
                    break;
                case "Deleted":
                    this.MappingState = MDSMappingState.Deleted;
                    break;
                default:
                    this.MappingState = MDSMappingState.NotSupported;
                    break;
            }


        }

        


        public override string ToString()
        {
            StringBuilder str = new StringBuilder();

            str.AppendLine(string.Format("Mapping Code {0}",this.MappingCode));
            str.AppendLine("Master" + MasterEntity.ToString());
            str.AppendLine("Slave" + SlaveEntity.ToString());
            str.AppendLine("Mapping State " + MappingState.ToString());
            str.AppendLine("Entity Sync State " + EntitySyncState.ToString());
            
            str.AppendLine("Attributes:");
            foreach (MasterToSlaveAttributeMapping m in MasterToSlaveAttributeMappings)
            {
                str.AppendLine(m.ToString());
            }
            str.AppendLine("************************************************************************");
            str.AppendLine();

            return str.ToString();
        }
    }
}
